#include "Ring.h"

#include <sstream>
#include <iomanip>
/*********************************************************/
void Ring::addNode(const std::string& addr)
{
	mutex.lock();
	for ( unsigned int i = 0; i<ring.size(); i++ ) {
		if ( addr == ring[i].addr ) {
			throw(std::logic_error("Trying to add a node to the ring, when the node is allready part of the ring!"));
		}
	}

	RingNode	node;
	node.addr = addr;
	node.clients.clear();
	ring.push_back(node);
	mutex.unlock();
}
/*********************************************************/
void Ring::removeNode(const std::string& addr)
{
	mutex.lock();
	for ( unsigned int i = 0; i<ring.size(); i++ ) {
		if ( addr == ring[i].addr ) {
			ring.erase(ring.begin()+i);
			break;
		}
	}
	mutex.unlock();
}
/*********************************************************/
void Ring::removeClient(const std::string& cAddr) 
{
	// Search for the client in the ring
	mutex.lock();
	for ( unsigned int i=0; i<ring.size(); i++ ) {
		for ( unsigned int c = 0; c<ring[i].clients.size(); c++ ) {
			if ( cAddr == ring[i].clients[c] ) {
				ring[i].clients.erase(ring[i].clients.begin()+c);
			}
		}
	}
	mutex.unlock();
}
/*********************************************************/
std::string Ring::addClient(const std::string& cAddr) 
{
	// Find the node with the lowest load in the ring
	mutex.lock();
	unsigned int load = 99999;
	std::string node = "";
	for ( unsigned int i=0; i<ring.size(); i++ ) {
		if ( load > ring[i].clients.size() ) {
			load = ring[i].clients.size();
			node = ring[i].addr;
		}
	}

	// Add the client connection to this node
	for ( unsigned int i =0; i<ring.size(); i++ ) {
		if ( node == ring[i].addr ) {
			ring[i].clients.push_back(cAddr);
		}
	}
	
	mutex.unlock();
	return node;
}
/*********************************************************/
std::string Ring::getName() const
{
	mutex.lock();
	std::string name = ringName;
	mutex.unlock();
	return name;
}
/*********************************************************/
void Ring::setName(const std::string& name)
{
	mutex.lock();
	ringName = name;
	mutex.unlock();
}
/*********************************************************/
std::string Ring::getAddr() const
{
	mutex.lock();
	std::string addr = ringAddr;
	mutex.unlock();
	return addr;
}
/*********************************************************/
void Ring::setAddr(const std::string& addr) 
{
	mutex.lock();
	ringAddr = addr;
	mutex.unlock();
}
/*********************************************************/
unsigned int Ring::size() const
{
	mutex.lock();
	unsigned int s = ring.size();
	mutex.unlock();
	return s;
}
/*********************************************************/
std::string Ring::loadOverview() const
{
	mutex.lock();
	std::ostringstream ostr;
	for ( unsigned int i=0; i<ring.size(); i++ ) {
		ostr << "Ring: " << ringName << std::endl;
		ostr << std::left << std::setw(25) << "Client" << std::setw(25) << "Server Node" << std::endl;
		for ( unsigned int b = 0; b<ring[i].clients.size(); b++) {
			ostr << std::setw(25) << ring[i].clients[b] << std::setw(25) << ring[i].addr << std::endl;
		}
	}
	mutex.unlock();
	return ostr.str();
}
/*********************************************************/
unsigned int Ring::load() const
{
	mutex.lock();
	unsigned int s = 0;
	for ( unsigned int i=0; i<ring.size(); i++ ) {
		s += ring[i].clients.size();
	}
	mutex.unlock();
	return s;
}
/*********************************************************/
Ring& Ring::operator=(const Ring& r2)
{
	ringAddr = r2.ringAddr;
	ringName = r2.ringName;
	ring = r2.ring;
	return ( *this );
}
/*********************************************************/
Ring::Ring(const Ring& r2)
{
	ringAddr = r2.ringAddr;
	ringName = r2.ringName;
	ring = r2.ring;
}
/*********************************************************/
Ring::Ring()
{
	ringAddr = "";
	ringName = "";
	ring.clear();
}
/*********************************************************/
Ring::~Ring()
{

}
/*********************************************************/
